﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace DotNetFunctionDemo.CommonLib
{
    public class Student
    {
        public int ID { get; set; }
        public String Name { get; set; }

        public DateTime Birthday { get; set; }

        private int Age { get; set; }
    }

    public class StudentOther
    {
        public int ID { get; set; }
        public String Name { get; set; }

        public DateTime Birthday { get; set; }

        private int Age { get; set; }
    }

    
    public class ObjectMapper
    {
        /// <summary>
        /// 反射方法
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="inObj"></param>
        /// <param name="outObj"></param>
        /// <returns></returns>
        public static TOut CopyObjectByReflection<TIn,TOut>(TIn inObj)
        {
            var props = typeof(TOut).GetProperties(BindingFlags.Public| BindingFlags.NonPublic);
            var outObj = CreateInstanceByActivator<TOut>();
            foreach (var outItem in props)
            {
                var inObjProp = inObj.GetType().GetProperty(outItem.Name);
                if (inObj != null)
                {
                    outItem.SetValue(outObj, inObjProp.GetValue(inObj));
                }
            }
            return outObj;
        }

        public static StudentOther CopyObjectByLambda(Student inObj)
        {
            System.Linq.Expressions.Expression<Func<Student, StudentOther>> exp = (o) => new StudentOther { Name = o.Name, Birthday = o.Birthday, ID = o.ID };
              Func<Student,StudentOther> func =  exp.Compile();
              return func(inObj);
        }

        public static readonly Func<Student, StudentOther> copyObj = CopyObjectByExpression();

        public static Func<Student, StudentOther> CopyObjectByExpression()
        {
            ParameterExpression paramExpes = Expression.Parameter(typeof(Student), "o");
            List<MemberBinding> mbList = new List<MemberBinding>();
            var props = typeof(StudentOther).GetProperties();
            foreach (var item in props)
            {
                var inTypeProp = typeof(Student).GetProperty(item.Name);
                //下面实现 Name = o.Name
                //studentOther o;
                MemberExpression mExp = Expression.Property(paramExpes, inTypeProp);
                //name = o.name;
                MemberBinding mb = Expression.Bind(item,mExp);
                mbList.Add(mb);
            }
            //new StudentOther();
            var newExp = Expression.New(typeof(StudentOther));
            //new StudentOther() {ID = o.ID, Name = o.Name, Birthday = o.Birthday}
            MemberInitExpression mInitExp = Expression.MemberInit(newExp,mbList.ToArray());
            //o => new StudentOther() { ID = o.ID, Name = o.Name, Birthday = o.Birthday }
            Expression<Func<Student, StudentOther>> lambda = Expression.Lambda<Func<Student, StudentOther>>(mInitExp, new ParameterExpression[] { paramExpes });
            //
            var func = lambda.Compile();
            return func;
        }
       


        public static void CopyObjectByJson(Student inObj,StudentOther outObj)
        {
            //StudentSecond ss = JsonConvert.DeserializeObject<StudentSecond>(JsonConvert.SerializeObject(s));
        }

        public static T MapTableToObject<T>(DataTable dt) where T : new()
        {
            if (dt == null || dt.Rows.Count <= 0)
            {
                return default(T);
            }
            var row = dt.Rows[0];
            var props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
            var instance = MapDataRowToObject<T>(row, dt.Columns);
            return instance;
        }

        public static List<T> MapTableToList<T>(DataTable dt) where T: new()
        {
            if (dt == null || dt.Rows.Count <=0)
            {
                return null;
            }
            var list = new List<T>(dt.Rows.Count);
            foreach (DataRow row in dt.Rows)
            {
                var instance = MapDataRowToObject<T>(row, dt.Columns);
                list.Add(instance);
            }
            return list;
        }
        public static T MapDataRowToObject<T>(DataRow row, DataColumnCollection cols) where T : new()
        {
            if (row == null)
            {
                return default(T);
            }
            T instance = (T)Activator.CreateInstance(typeof(T));
            var props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
            foreach (DataColumn col in cols)
            {
                var objProp = (from p in props where string.Compare(p.Name, col.ColumnName, true) == 0 select p).FirstOrDefault();
                if (objProp == null)
                {
                    continue;
                }
                if (objProp.CanWrite)
                {
                    //这里没有考虑类型转化 默认情况下保持一直 table列和class中的能转化。
                    var val = row[objProp.Name];
                    objProp.SetValue(instance, val);
                }
            }
            return instance;
        }
        public static T CreateInstance<T>()
        {
            var t = typeof(T);
            var instance = System.Reflection.Assembly.Load(t.Assembly.GetName()).CreateInstance(t.FullName);
            return (T)instance;
        }

        public static T CreateInstanceByActivator<T>()
        {
            var t = typeof(T);
            var instance = (T)Activator.CreateInstance(typeof(T));
            return instance;
        }


    }
}
